﻿using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Localization;
using Qianke.Core.Common.Interface;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Volo.Abp;
using Volo.Abp.Application.Services;
using Volo.Abp.Caching;
using Volo.Abp.DistributedLocking;
using Volo.Abp.EntityFrameworkCore;
using Volo.Abp.Localization;
using Volo.Abp.ObjectMapping;
using Volo.Abp.Uow;

namespace Qianke.Core.Saas.Application.BaseService
{
    public class BusinessService<TDbContext> : ApplicationService
        where TDbContext : IEfCoreDbContext
    {
        private TDbContext db = default(TDbContext);

        protected override IStringLocalizer CreateLocalizer()
        {
            var localizer = StringLocalizerFactory.CreateDefaultOrNull();
            if (localizer == null)
            {
                if (LocalizationResource != null)
                    return StringLocalizerFactory.Create(LocalizationResource);
                throw new AbpException($"Set {nameof(LocalizationResource)} or define the default localization resource type (by configuring the {nameof(AbpLocalizationOptions)}.{nameof(AbpLocalizationOptions.DefaultResourceType)}) to be able to use the {nameof(L)} object!");
            }
            return localizer;
        }
        protected ITokenInfo tokenModel => LazyServiceProvider.GetRequiredService<ITokenInfo>();

        protected IDbContextProvider<TDbContext> dbContextProvider => LazyServiceProvider.GetRequiredService<IDbContextProvider<TDbContext>>();

        public BusinessService()
        {

        }

        protected async Task<TDbContext> GetDB()
        {
            if (db == null)
            {
                if (UnitOfWorkManager.Current != null)
                    db = await dbContextProvider.GetDbContextAsync();
                else
                    db = LazyServiceProvider.GetRequiredService<TDbContext>();
            }
            return db;
        }


        protected Task<TResultDto> LockHandle<TResultDto>(string lockKeyName, Func<Task<TResultDto>> func, TimeSpan? timeOut = null)
        {
            return LockHandle(new List<string> { lockKeyName }, func, timeOut);
        }

        protected async Task<TResultDto> LockHandle<TResultDto>(IEnumerable<string> lockKeyNames, Func<Task<TResultDto>> func, TimeSpan? timeOut = null)
        {
            var _distributedLock = LazyServiceProvider.GetRequiredService<IAbpDistributedLock>();
            var handleList = new List<IAbpDistributedLockHandle>();
            try
            {
                foreach (var lockKeyName in lockKeyNames)
                {
                    var handle = await _distributedLock.TryAcquireAsync(lockKeyName, timeOut ?? TimeSpan.FromSeconds(30));
                    if (handle == null)
                        throw new Exception($"获取异步锁{lockKeyName}失败,请稍后重试");
                    handleList.Add(handle);
                }
                return await func();
            }
            finally
            {
                foreach (var handle in handleList)
                    await handle.DisposeAsync();
            }
        }

        protected Task<TResultDto> LockHandle<TResultDto>(string keyNamePrefix, IEnumerable<long> ids, Func<Task<TResultDto>> func, TimeSpan? timeOut = null)
        {
            return LockHandle(ids.Select(u => $"{keyNamePrefix}:{u}"), func, timeOut);
        }

        protected TDestination MapTo<TDestination>(object source)
        {
            return (TDestination)ObjectMapper.Map(source.GetType(), typeof(TDestination), source);
        }

        protected List<TDestination> MapTo<TDestination>(IEnumerable source)
        {
            var result = new List<TDestination>();
            foreach (var item in source)
                result.Add(MapTo<TDestination>(item));
            return result;
        }
    }
}
